package org.common.util;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

import org.common.annotation.XmlList;
import org.common.exception.MetadataException;
import org.common.exception.UtilException;
import org.jdom.Attribute;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;

public class XmlUtil {

	public static <T> List<T> createXmlDtoList(String businessTypePath, Class<T> clazz) throws Exception {
		File file = new File(businessTypePath);
		SAXBuilder builder = new SAXBuilder();
		Document doc = null;
		try {
			doc = builder.build(file);
		} catch (IOException e) {
			throw new MetadataException("读入文件发生异常", e);
		} catch (JDOMException e) {
			throw new MetadataException("生成document发生异常", e);
		}
		Element root = doc.getRootElement();

		List<?> children = root.getChildren();
		List<T> list = new ArrayList<T>();
		for (int i = 0; i < children.size(); i++) {
			Element child = (Element) children.get(i);
			list.add(createXmlDto(child, clazz));
		}

		return list;
	}

	private static <T> T createXmlDto(Element ele, Class<T> clazz) throws Exception {

		if (clazz == String.class) {
			Constructor<T> t = clazz.getConstructor(String.class);
			return t.newInstance(ele.getText());
		}

		List<?> attrs = ele.getAttributes();
		T obj = clazz.newInstance();
		for (int i = 0; i < attrs.size(); i++) {
			Attribute attr = (Attribute) attrs.get(i);
			Field field = findField(attr.getName(), clazz);
			field.setAccessible(true);
			field.set(obj, attr.getValue());

		}
		if (ele.getChildren() != null) {
			for (int i = 0; i < ele.getChildren().size(); i++) {
				Element child = (Element) (ele.getChildren().get(i));
				Field field = findField(child.getName(), clazz);
				field.setAccessible(true);

				if (field.isAnnotationPresent(XmlList.class)) {
					List<Object> parameters = new ArrayList<Object>();
					if (child.getChildren() != null && child.getChildren().size() > 0) {
						for (int j = 0; j < child.getChildren().size(); j++) {
							Element realChild = (Element) (child.getChildren().get(j));
							parameters.add(
									createXmlDto(realChild, findClassName(defaultNameConvert(realChild.getName(), true),
											field.getDeclaringClass().getDeclaredClasses())));
						}
					}
					field.set(obj, parameters);
				} else {
					if (field != null) {
						Object parameter = createXmlDto(child, field.getType());
						field.set(obj, parameter);
					}
				}

			}
		}
		return obj;
	}

	private static Class<?> findClassName(String className, Class<?>[] clazzs) {
		for (Class<?> clazz : clazzs) {
			if (clazz.getSimpleName().equals(className)) {
				return clazz;
			}
		}
		return null;
	}

	private static Field findField(String name, Class<?> clazz) throws UtilException {
		Field field = null;
		try {
			field = clazz.getDeclaredField(defaultNameConvert(name, false));
		} catch (NoSuchFieldException e) {
			try {
				field = clazz.getDeclaredField(name.replaceAll("-", "_"));
			} catch (NoSuchFieldException e1) {
				throw new UtilException(String.format("未从[%s]找到属性[%s]", clazz.getName(), name));
			}
		}
		return field;
	}

	private static String defaultNameConvert(String name, boolean isTypeName) {
		String names[] = name.split("-");
		String newName = "";
		for (String oldName : names) {
			newName += oldName.substring(0, 1).toUpperCase() + oldName.substring(1);
		}
		return isTypeName ? newName : newName.substring(0, 1).toLowerCase() + newName.substring(1);
	}

}
